<?php

version_compare(PHP_VERSION, '7.0.0', '>=') or die('required PHP version greater than 7.0.0');


class UnicodeToLiteral
{

    const DB_CONFIG = [
        'bind' => [
            'host' => '10.168.177.85',
            'username' => 'securitykeeper',
            'passwd' => 'usY%lAtBEWAt6tKj',
            'dbname' => 'secure_information',
            'port' => '3306',
        ],
    ];

    const TABLE_NAME = 'tbl_eshop_bind';

    const DB_BIND = 'bind';

    private $dbInstances = [];

    private $lastQueryMembers = [];

    private $lastQuerySql;

    private $queryResult = [];

    public function run()
    {
    	if($data = $this->getAllUnicodeNickname()){
    		array_walk($data, function(&$val){
    			$val['eshop_nickname'] = $this->unicode2Literal($val['eshop_nickname']);
    		});
    		$count = 0;
    		foreach ($data as $info) {
				echo implode(',', $info),PHP_EOL;
				$this->updateUserInfo((int)$info['id'], ['eshop_nickname' => $info['eshop_nickname']]);
    			$count++;
    		}
    		echo count($data);
    	}
    	var_dump($data);
    }

    /**
     * @param string $dbName
     * @param bool $new
     * @return mixed
     * @throws Exception
     */
    private function getDbInstance(string $dbName, bool $new = false) : MySQLi
    {
        if(empty($this->dbInstances[$dbName])){
            if(!array_key_exists($dbName, static::DB_CONFIG)){
                throw new Exception('this db is not set yet');
            }
            $this->dbInstances[$dbName] = new MySQLi(...array_values(static::DB_CONFIG[$dbName]));
            if($this->dbInstances[$dbName]->connect_error){
                throw new Exception('Connect Error (' . $mysqli->connect_errno . ') '
            . $mysqli->connect_error);
            }
            $this->dbInstances[$dbName]->set_charset('utf8');
        }
        return $this->dbInstances[$dbName];
    }

    /**
     * mysql is using C escape , PHP also using C escape so search \ needs \\\\(\\ means \, after double escape it remains \)
     * @param string|null $timeStr
     * @return array
     */
    public function getAllUnicodeNickname() : array
    {
        $sql = "SELECT id,eshop_nickname ,eshop_username FROM ".static::TABLE_NAME." WHERE eshop_nickname LIKE '%\\\\\\\\u%' ORDER BY id ASC";
        if($data = $this->query($sql, $this->getDbInstance(static::DB_BIND))){
			$this->lastQueryMembers = $data;
        }
        return $this->lastQueryMembers;
    }

    /**
     * unicode2Literal
     *
     * @param  string $str
     * @return string
     */
    private function unicode2Literal(string $str) : string
    {
    	return stripos($str, '\\u') !== false ? json_decode('"'.$str.'"') ?: json_decode('"'.$this->unicodePreProcess($str).'"') : $str;
    }

    /**
     * \\\\ match \ in finally same as mysql search string, because both PHP and PCRE using C escape
     * @param  string $str
     * @return string
     */
    private function unicodePreProcess(string $str) : string
    {
    	return preg_replace('#\\\\u[\dA-F]{0,3}$#i', '', $str);
    }

    private function buildUpdateSqlSentence(array $data) : string
    {
    	$sql = '';
    	if(count($data)){
    		$sqlTpl = '`%s` = "%s",';
    		$sql = 'SET ';
    		foreach ($data as $key => $val) {
    			$sql .= sprintf($sqlTpl, $key, $val);
    		}
    		$sql = trim($sql, ',');
    	}
    	return $sql;
    }

    /**
     * @param array $phones
     * @param string $timeStr
     * @return array|bool|mixed|mysqli_result
     */
    public function updateUserInfo(int $id, array $data)
    {
    	$this->lastQuerySql = $sql = 'UPDATE '.static::TABLE_NAME.' '.$this->buildUpdateSqlSentence($data).' WHERE id ='.$id;
    	return $this->queryResult[$id] = $this->query($sql, $this->getDbInstance(static::DB_BIND));
    }

    /**
     * @param string $sql
     * @param MySQLi $dbInstance
     * @return bool|mixed|mysqli_result
     */
    private function query(string $sql, MySQLi $dbInstance)
    {
    	$this->lastQuerySql = $sql;
        if(($result = $dbInstance->query($sql)) && $result instanceof mysqli_result){
            return $data = $result->fetch_all(MYSQLI_ASSOC);
        }
        return $result;
    }

    public function getLastSql()
    {
    	return $this->lastQuerySql;
    }
}

$converter = new UnicodeToLiteral();
$converter->run();
echo $converter->getLastSql();
